library(knitr)
library(tidyr)
library(dplyr)
library(ggplot2)
library(plotly)
library(caret)
library(tibble)
library(ggpubr)
Raport wykonany w ramach kursu Zaawansowana eksploracja danych, na semestrze zimowym 2024/2025.
Raport służy do analizy bazy danych materiałów wykorzystywanych w tworzeniu baterii.
Wykorzystane dane pochodzą z inicjatywy naukowej Departamentu Energii USA Materials Project. Pobrane zostały ze strony kursu dnia 24.11.2024.
Zbiór danych składa się z następujących kolumn:
Battery ID - identyfikator baterii.Battery Formula - wzór chemiczny materiału
baterii.Working Ion - główny jon, który odpowiada za transport
ładunku w baterii.Formula Charge - wzór chemiczny materiału baterii w
stanie naładowanym.Formula Discharge - wzór chemiczny materiału baterii w
stanie rozładowanym.Max Delta Volume - zmiana objętości w % dla danego
kroku napięcia za pomocą wzoru: max(charge, discharge)/min(charge,
discharge) -1.Average Voltage - średnie napięcie dla poszczególnego
kroku napięcia.Gravimetric Capacity - pojemność grawimetryczna, czyli
ilość energii na jednostkę masy (mAh/g).Volumetric Capacity - pojemność wolumetryczna, czyli
ilość energii na jednostkę objętości (mAh/cm³).Gravimetric Energy - gęstość energii w odniesieniu do
masy baterii (Wh/kg).Volumetric Energy - gęstość energii w odniesieniu do
objętości baterii (Wh/L).Atomic Fraction Charge - udział atomowy składników w
stanie naładowanym.Atomic Fraction Discharge - udział atomowy składników w
stanie rozładowanym.Stability Charge - wskaźnik stabilności materiału w
stanie naładowanym.Stability Discharge - wskaźnik stabilności materiału w
stanie rozładowanym.Steps - liczba odrębnych kroków napięcia od pełnego
naładowania do rozładowania, oparta na stabilnych stanach
pośrednich.Max Voltage Step - maksymalna bezwzględna różnica
między sąsiednimi krokami napięcia.Dane były przetworzone i wyczyszczone przez autorów ale upewniamy się że nie bedzie danych brakujących.
df <- read.csv("data/mp_batteries.csv", header = T)
df <- df[complete.cases(df),]
Wyświetlenie wszystkich zmiennych oraz podstawowych statystyk. Dla wartości tekstowych zwrócone zostały: liczba unikalnych wartości i najczęstsza wartość.
kable(head(df[1:5]))
| Battery.ID | Battery.Formula | Working.Ion | Formula.Charge | Formula.Discharge |
|---|---|---|---|---|
| mp-30_Al | Al0-2Cu | Al | Cu | Al2Cu |
| mp-1022721_Al | Al1-3Cu | Al | AlCu | Al3Cu |
| mp-8637_Al | Al0-5Mo | Al | Mo | Al5Mo |
| mp-129_Al | Al0-12Mo | Al | Mo | Al12Mo |
| mp-91_Al | Al0-12W | Al | W | Al12W |
| mp-1055908_Al | Al0-12Mn | Al | Mn | MnAl12 |
summary_fun <- function(x){
mt <- table(x)
c(n_distinct(x), names(mt)[which.max(mt)])
}
sdf <- mapply(summary_fun, df[1:5])
rownames(sdf) <- c('Liczba unikalnych','Najczęstsza wartość')
kable(sdf)
| Battery.ID | Battery.Formula | Working.Ion | Formula.Charge | Formula.Discharge | |
|---|---|---|---|---|---|
| Liczba unikalnych | 4351 | 3301 | 10 | 2096 | 3173 |
| Najczęstsza wartość | mp-1001925_Mg | Li0-1V2OF5 | Li | MnO2 | LiCoPO4 |
kable(head(df[6:11]))
| Max.Delta.Volume | Average.Voltage | Gravimetric.Capacity | Volumetric.Capacity | Gravimetric.Energy | Volumetric.Energy |
|---|---|---|---|---|---|
| 3.043399 | 0.0890331 | 1368.481 | 5562.790 | 121.84009 | 495.27253 |
| 1.243653 | -0.0215863 | 1112.937 | 4418.980 | -24.02423 | -95.38962 |
| 4.762574 | 0.1227568 | 1741.504 | 7175.702 | 213.78156 | 880.86651 |
| 12.723893 | 0.0431214 | 2298.811 | 7346.232 | 99.12801 | 316.78006 |
| 12.494598 | 0.0292342 | 1900.745 | 7332.719 | 55.56677 | 214.36621 |
| 18.236156 | 0.0397314 | 2547.693 | 7592.916 | 101.22330 | 301.67688 |
kable(summary(df[6:11]))
| Max.Delta.Volume | Average.Voltage | Gravimetric.Capacity | Volumetric.Capacity | Gravimetric.Energy | Volumetric.Energy | |
|---|---|---|---|---|---|---|
| Min. : 0.00002 | Min. :-7.755 | Min. : 5.176 | Min. : 24.08 | Min. :-583.5 | Min. :-2208.1 | |
| 1st Qu.: 0.01747 | 1st Qu.: 2.226 | 1st Qu.: 88.108 | 1st Qu.: 311.62 | 1st Qu.: 211.7 | 1st Qu.: 821.6 | |
| Median : 0.04203 | Median : 3.301 | Median : 130.691 | Median : 507.03 | Median : 401.8 | Median : 1463.8 | |
| Mean : 0.37531 | Mean : 3.083 | Mean : 158.291 | Mean : 610.62 | Mean : 444.1 | Mean : 1664.0 | |
| 3rd Qu.: 0.08595 | 3rd Qu.: 4.019 | 3rd Qu.: 187.600 | 3rd Qu.: 722.75 | 3rd Qu.: 614.4 | 3rd Qu.: 2252.3 | |
| Max. :293.19322 | Max. :54.569 | Max. :2557.627 | Max. :7619.19 | Max. :5926.9 | Max. :18305.9 |
kable(head(df[12:17]))
| Atomic.Fraction.Charge | Atomic.Fraction.Discharge | Stability.Charge | Stability.Discharge | Steps | Max.Voltage.Step |
|---|---|---|---|---|---|
| 0.0 | 0.6666667 | 0.0000000 | 0.0000000 | 1 | 0 |
| 0.5 | 0.7500000 | 0.0740612 | 0.0962458 | 1 | 0 |
| 0.0 | 0.8333333 | 0.4114601 | 0.0452120 | 1 | 0 |
| 0.0 | 0.9230769 | 0.0000000 | 0.0114456 | 1 | 0 |
| 0.0 | 0.9230769 | 0.0000000 | 0.0000000 | 1 | 0 |
| 0.0 | 0.9230769 | 0.1454643 | 0.0000000 | 1 | 0 |
kable(summary(df[12:17]))
| Atomic.Fraction.Charge | Atomic.Fraction.Discharge | Stability.Charge | Stability.Discharge | Steps | Max.Voltage.Step | |
|---|---|---|---|---|---|---|
| Min. :0.00000 | Min. :0.007407 | Min. :0.00000 | Min. :0.00000 | Min. :1.000 | Min. : 0.0000 | |
| 1st Qu.:0.00000 | 1st Qu.:0.086957 | 1st Qu.:0.03301 | 1st Qu.:0.01952 | 1st Qu.:1.000 | 1st Qu.: 0.0000 | |
| Median :0.00000 | Median :0.142857 | Median :0.07319 | Median :0.04878 | Median :1.000 | Median : 0.0000 | |
| Mean :0.03986 | Mean :0.159077 | Mean :0.14257 | Mean :0.12207 | Mean :1.167 | Mean : 0.1503 | |
| 3rd Qu.:0.04762 | 3rd Qu.:0.200000 | 3rd Qu.:0.13160 | 3rd Qu.:0.09299 | 3rd Qu.:1.000 | 3rd Qu.: 0.0000 | |
| Max. :0.90909 | Max. :0.993333 | Max. :6.48710 | Max. :6.27781 | Max. :6.000 | Max. :26.9607 |
Na podstawie podstawowych statystyk można stwierdzić, że istnieją
wartości odstające (np. Gravimetric.Capacity, Volumetric.Capacity) oraz
że część wartości została wprowadzona lub zmierzona niepoprawnie
(Average.Voltage) Wartości odstające zostaną usunięte przy użyciu
z-score.
z_threshold <- 3
outliers_threshold <- df %>%
select_if(is.numeric) %>%
summarise(across(everything(), list(
"odcięcie dolne" = ~ -z_threshold * sd(.x) + mean(.x),
"odcięcie górne" = ~ z_threshold * sd(.x) + mean(.x)
))) %>%
pivot_longer(
cols = everything(),
names_to = c("column_name",".value"),
names_pattern = "(.*)_(.*)"
)
outliers_threshold <- outliers_threshold %>%
column_to_rownames(var='column_name')
outliers_count <- df %>%
select_if(is.numeric) %>%
summarise(across(everything(),
list(
outliers_count = ~ sum(abs(scale(.x)) > z_threshold))
)) %>%
pivot_longer(
cols = everything(),
names_to = "column_name",
values_to = "liczba odciętych"
)
outliers_count <- outliers_count %>%
column_to_rownames(var='column_name')
cbind(outliers_threshold, outliers_count) %>% knitr::kable()
| odcięcie dolne | odcięcie górne | liczba odciętych | |
|---|---|---|---|
| Max.Delta.Volume | -20.1801987 | 20.9308261 | 4 |
| Average.Voltage | -2.3830258 | 8.5493113 | 18 |
| Gravimetric.Capacity | -336.4500340 | 653.0318129 | 43 |
| Volumetric.Capacity | -1080.9352788 | 2302.1834762 | 62 |
| Gravimetric.Energy | -609.0380088 | 1497.2507692 | 40 |
| Volumetric.Energy | -2229.3472896 | 5557.4441170 | 39 |
| Atomic.Fraction.Charge | -0.2258255 | 0.3055370 | 81 |
| Atomic.Fraction.Discharge | -0.2020458 | 0.5202002 | 94 |
| Stability.Charge | -0.9922662 | 1.2773994 | 52 |
| Stability.Discharge | -0.9348829 | 1.1790262 | 73 |
| Steps | -0.2241607 | 2.5583368 | 99 |
| Max.Voltage.Step | -1.7399143 | 2.0404938 | 66 |
count_before <- nrow(df)
df <- df %>% filter(if_all(where(~ is.numeric(.)), ~ abs(scale(.)) < z_threshold))
count_after <- nrow(df)
Dla najlepszej jakości danych wybrano próg 3, przed wyczyszczeniem liczba wierszy wynosiła: 4351, a po 3935.
Poniżej przedstawiono rozkład poszczególnych wartości oraz relacji między wybranymi parami atrybutów.
p <- ggplot(df, aes(x = `Working.Ion`)) +
geom_bar(fill = "blue", color = "black") +
labs(x='główny jon', y='Liczność', title='Rozkład parametru główny jon')
ggplotly(p)
present_variable <- function(data, column, binwidth, columnName) {
p <- ggplot(data, aes(x=column)) +
geom_histogram( binwidth=binwidth) +
geom_vline(aes(xintercept = sd(data$column)), linetype = "dashed", size=1) +
labs(x=columnName, y='Liczność', title=paste('Rozkład parametru', columnName))
ggplotly(p)
}
present_variable(df, df$"Max.Delta.Volume", binwidth = 0.01, 'maksymalna zmiana objętości')
present_variable(df, df$"Average.Voltage", binwidth = 0.2, 'średnie napięcie')
present_variable(df, df$"Gravimetric.Capacity", binwidth = 10, 'pojemność grawimetryczna')
present_variable(df, df$"Volumetric.Capacity", binwidth = 40, 'pojemność wolumetryczna')
present_variable(df, df$"Gravimetric.Energy", binwidth = 40, 'gęstość energii w odniesieniu do masy baterii')
present_variable(df, df$"Volumetric.Energy", binwidth = 120, 'gęstość energii w odniesieniu do objętości baterii')
present_variable(df, df$"Atomic.Fraction.Charge", binwidth = 0.01, 'udział atomowy składników w stanie naładowanym')
present_variable(df, df$"Atomic.Fraction.Discharge", binwidth = 0.01, 'udział atomowy składników w stanie rozładowanym')
present_variable(df, df$"Stability.Charge", binwidth = 0.01, 'wskaźnik stabilności materiału w stanie naładowanym')
present_variable(df, df$"Stability.Discharge", binwidth = 0.01, 'wskaźnik stabilności materiału w stanie rozładowanym')
present_variable(df, df$"Steps", binwidth = 0.5, 'liczba odrębnych kroków napięcia od pełnego naładowania do rozładowania')
present_variable(df, df$"Max.Voltage.Step", binwidth = 1, 'maksymalna bezwzględna różnica między sąsiednimi krokami napięcia')